package com.neusoft.hifly.gateway;

import java.util.ArrayList;
import java.util.List;

import org.redisson.api.RList;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionRepository;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSON;

import com.neusoft.hifly.gateway.utils.RedisKeys;
import com.neusoft.hifly.lock.utils.Log;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

/**
 * 网关自定义RedisRouteDefinitionRepository，初始化加载路由
 * <p>
 * 从redis中获取路由配置
 * <p>
 * 该类会自动调用，通过注册中心的HeartbeatEvent事件
 * <p>
 * 通过RefreshRoutesEvent事件刷新动态路由配置
 */
@Component
public class RedisRouteDefinitionWriter implements RouteDefinitionRepository {

	@Autowired(required = false)
	private RedissonClient redisson;

	/**
	 * 读取缓存中的配置，进行动态加载
	 */
	@Override
	public Flux<RouteDefinition> getRouteDefinitions() {
		final List<RouteDefinition> definitionList = new ArrayList<RouteDefinition>(0);
		try {
			final RList<Object> list = redisson.getList(RedisKeys.GATEWAY_ROUTE.getKey());

			list.readAll().forEach(json -> {
				final RouteDefinition routeDefinition = JSON.parseObject(String.valueOf(json), RouteDefinition.class);
				definitionList.add(routeDefinition);
			});
		} catch (final Exception e) {
			Log.error("加载路由信息失败！", e);
		}
		Log.info(String.format("redis 中路由定义条数： {%d}， {%s}", definitionList.size(), definitionList));
		return Flux.fromIterable(definitionList);
	}

	/**
	 * 新增配置
	 */
	@Override
	public Mono<Void> save(final Mono<RouteDefinition> route) {
		return route.flatMap(r -> {
			try {
				Log.info(String.format("保存路由信息{}", r));
				final RList<Object> list = redisson.getList(RedisKeys.GATEWAY_ROUTE.getKey());
				list.add(JSON.toJSONString(r));
			} catch (final Exception e) {
				Log.error("保存路由信息失败！", e);
			}
			return Mono.empty();
		});
	}

	/**
	 * 删除配置
	 */
	@Override
	public Mono<Void> delete(final Mono<String> routeId) {
		try {
			routeId.subscribe(id -> {
				Log.info(String.format("删除路由信息{}", id));
				final RList<Object> list = redisson.getList(RedisKeys.GATEWAY_ROUTE.getKey());
				list.readAll().forEach(json -> {
					final RouteDefinition routeDefinition = JSON.parseObject(String.valueOf(json),
							RouteDefinition.class);
					if (routeDefinition.getId().equals(id)) {
						list.remove(json);
					}
				});

			});
		} catch (final Exception e) {
			Log.error("删除路由信息失败！", e);
		}
		return Mono.empty();
	}

}
